﻿using Autofac;
using Autofac.Extras.DynamicProxy;
using SqlSugar;
using SunnyPaine.Autofac.Extension.SqlSugar.Entities;
using SunnyPaine.Autofac.Extension.SqlSugar.Interceptor;
using SunnyPaine.Autofac.Extension.Stereotype;
using SunnyPaine.Autofac.Extension.Stereotype.Entities;
using SunnyPaine.Autofac.Extension.Stereotype.Selector;
using SunnyPaine.SqlSugar.Autofac.Stereotype.Selector;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;

namespace SunnyPaine.Autofac.Extension.SqlSugar.IOC
{
    /// <summary>
    /// 基于 <see cref="Injecter"/> 的扩展。包含 SqlSugar 的扩展信息。
    /// </summary>
    public static class InjecterSqlSugar
    {
        /// <summary>
        /// 启用SqlSugar扩展。
        /// </summary>
        /// <param name="builder"></param>
        /// <param name="connectionInfo">数据库连接配置信息。</param>
        public static void UseSqlSugar(this ContainerBuilder builder, List<ConnectionInfo> connectionInfo)
        {
            SqlSugarScope scope = SqlSugarManager.CreateDBA(connectionInfo);
            builder.Register(c => scope).As<ISqlSugarClient>();

            //注册事务管理拦截器
            builder.RegisterType<TransactionInterceptor>()
                   .AsSelf()
                   .OnActivating(p => p.Instance.Init(scope, connectionInfo));

            //Register(builder);
        }

        /// <summary>
        /// 注册实例。请勿与 <see cref="Injecter.Register(ContainerBuilder)"/> 混用，否则可能导致实例污染。
        /// </summary>
        /// <param name="builder"></param>
        public static void RegisterEx(this ContainerBuilder builder)
        {
            List<InstanceInfo> iis = Injecter.InstanceInfos.OrderBy(p => p.Sort).ToList();
            List<InstanceInfoEx> infoExs = ToInstanceInfoExs(iis);

            foreach (InstanceInfoEx infoEx in infoExs)
            {
                if (infoEx.ComponentType == ComponentType.Configure)
                {
                    var registrationBuilder = builder.Register(c => infoEx.Instance);
                    foreach (Type typeInterface in infoEx.InterfaceTypes)
                    {
                        registrationBuilder.Named(infoEx.Name, typeInterface).As(typeInterface);
                    }
                    if (infoEx.Single)
                    {
                        registrationBuilder.SingleInstance();
                    }
                }
                else
                {
                    if (infoEx.ImplementType.IsGenericType)//泛型
                    {
                        var registrationBuilder = builder.RegisterGeneric(infoEx.ImplementType);
                        if (infoEx.UseTransaction && infoEx.ComponentType != ComponentType.DataAccess)
                        {
                            foreach (Type typeInterface in infoEx.InterfaceTypes)
                            {
                                registrationBuilder.Named(infoEx.Name, typeInterface).As(typeInterface);
                            }
                            if (infoEx.Single)
                            {
                                registrationBuilder.EnableInterfaceInterceptors()//启用接口拦截
                                                   .InterceptedBy(typeof(TransactionInterceptor))//指定拦截器
                                                   .PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector())
                                                   .SingleInstance();
                            }
                            else
                            {
                                registrationBuilder.EnableInterfaceInterceptors()//启用接口拦截
                                                   .InterceptedBy(typeof(TransactionInterceptor))//指定拦截器
                                                   .PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector());
                            }
                        }
                        else
                        {
                            foreach (Type typeInterface in infoEx.InterfaceTypes)
                            {
                                registrationBuilder.Named(infoEx.Name, typeInterface).As(typeInterface);
                            }
                            if (infoEx.Single)
                            {
                                registrationBuilder.PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector())
                                                   .SingleInstance();
                            }
                            else
                            {
                                registrationBuilder.PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector());
                            }
                        }
                    }
                    else
                    {
                        var registrationBuilder = builder.RegisterType(infoEx.ImplementType);
                        if (infoEx.UseTransaction && infoEx.ComponentType != ComponentType.DataAccess)//启用了事务，且不是dao层
                        {
                            foreach (Type typeInterface in infoEx.InterfaceTypes)
                            {
                                registrationBuilder.Named(infoEx.Name, typeInterface).As(typeInterface);
                            }
                            if (infoEx.Single)
                            {
                                registrationBuilder.EnableInterfaceInterceptors()//启用接口拦截
                                                   .InterceptedBy(typeof(TransactionInterceptor))//指定拦截器
                                                   .PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector())
                                                   .SingleInstance();
                            }
                            else
                            {
                                registrationBuilder.EnableInterfaceInterceptors()//启用接口拦截
                                                   .InterceptedBy(typeof(TransactionInterceptor))//指定拦截器
                                                   .PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector());
                            }
                        }
                        else
                        {
                            foreach (Type typeInterface in infoEx.InterfaceTypes)
                            {
                                registrationBuilder.Named(infoEx.Name, typeInterface).As(typeInterface);
                            }
                            if (infoEx.Single)
                            {
                                registrationBuilder.PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector())
                                                   .SingleInstance();
                            }
                            else
                            {
                                registrationBuilder.PropertiesAutowired(new AutowiredPropertySelector())
                                                   .PropertiesAutowired(new ResourcePropertySelector());
                            }
                        }
                    }
                }
            }
        }

        private static List<InstanceInfoEx> ToInstanceInfoExs(List<InstanceInfo> infos)
        {
            List<InstanceInfoEx> list = new List<InstanceInfoEx>();
            foreach (InstanceInfo info in infos)
            {
                InstanceInfoEx ex = new InstanceInfoEx()
                {
                    ComponentType = info.ComponentType,
                    ImplementType = info.ImplementType,
                    Instance = info.Instance,
                    InterfaceTypes = info.InterfaceTypes,
                    Name = info.Name,
                    Sort = info.Sort,
                    Single = info.Single
                };
                if (info.ComponentType == ComponentType.Configure)
                {
                    list.Add(ex);
                    continue;
                }

                TransactionAttribute transactionAttribute = info.ImplementType.GetCustomAttribute<TransactionAttribute>();
                ex.UseTransaction = transactionAttribute != null;
                list.Add(ex);
            }

            return list;
        }
    }
}
